package com.zoe.onelink.business.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>标题: Request包装类</p>
 * <p>描述: 包装请求参数，方便后续spring对参数的默认处理</p>
 * <p>版权: Copyright (c) 2016</p>
 * <p>公司: </p>
 *
 * @version: 1.0
 * @author: ffs
 */
public class ApiHttpRequestWrapper extends HttpServletRequestWrapper {
    private final HashMap paramsMap;

    public ApiHttpRequestWrapper(HttpServletRequest request, Map extendMap) {
        this(request, extendMap, false);
    }

    public ApiHttpRequestWrapper(HttpServletRequest request, Map paramMap, boolean inheritParams) {
        super(request);
        paramsMap = inheritParams ? new HashMap(request.getParameterMap()) : new HashMap();
        for (Object o : paramMap.entrySet()) {
            Map.Entry entry = (Map.Entry) o;
            String name = String.valueOf(entry.getKey());
            Object value = entry.getValue();
            final String[] valueArray;
            if (value == null) {
                // Null values are explicitly added (so, among other
                // things, we can hide inherited param values).
                valueArray = new String[]{null};
            } else if (value instanceof String[]) {
                // String[] arrays are just passed through
                valueArray = (String[]) value;
            } else if (value instanceof Collection) {
                // Collections are converted to String[], with
                // String.valueOf() used on elements
                Collection col = (Collection) value;
                valueArray = new String[col.size()];
                int i = 0;
                for (Object aCol : col) {
                    valueArray[i++] = String.valueOf(aCol);
                }
            } else if (value.getClass().isArray()) {
                // Other array types are too converted to String[], with
                // String.valueOf() used on elements
                int len = Array.getLength(value);
                valueArray = new String[len];
                for (int i = 0; i < len; ++i) {
                    valueArray[i] = String.valueOf(Array.get(value, i));
                }
            } else {
                // All other values (including strings) are converted to a
                // single-element String[], with String.valueOf applied to
                // the value.
                valueArray = new String[]{String.valueOf(value)};
            }
            String[] existingParams = (String[]) paramsMap.get(name);
            int el = existingParams == null ? 0 : existingParams.length;
            if (el == 0) {
                // No original params, just put our array
                paramsMap.put(name, valueArray);
            } else {
                int vl = valueArray.length;
                if (vl > 0) {
                    // Both original params and new params, prepend our
                    // params to original params
                    String[] newValueArray = new String[el + vl];
                    System.arraycopy(valueArray, 0, newValueArray, 0, vl);
                    System.arraycopy(existingParams, 0, newValueArray, vl, el);
                    paramsMap.put(name, newValueArray);
                }
            }
        }
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] value = ((String[]) paramsMap.get(name));
        return value != null ? value.clone() : null;
    }

    @Override
    public String getParameter(String name) {
        String[] values = (String[]) paramsMap.get(name);
        return values != null && values.length > 0 ? values[0] : null;
    }

    @Override
    public Enumeration getParameterNames() {
        return Collections.enumeration(paramsMap.keySet());
    }

    @Override
    public Map getParameterMap() {
        HashMap clone = (HashMap) paramsMap.clone();
        for (Object o : clone.entrySet()) {
            Map.Entry entry = (Map.Entry) o;
            entry.setValue(((String[]) entry.getValue()).clone());
        }
        return Collections.unmodifiableMap(clone);
    }
}
